package com.hanter.android.radlib.crypto;

import android.text.TextUtils;
import android.util.Log;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

public class DigestUtils {

    public static final String TAG = DigestUtils.class.getSimpleName();

    public static String md5(String message) {
        String md5 = "";
        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            byte[] messageBytes = message.getBytes(StandardCharsets.UTF_8);
            byte[] md5Bytes = md.digest(messageBytes); // 获得MD5字节数组, 16*8 = 128位
            md5 = md5ToHex(md5Bytes); // 转换为16进制字符串
        } catch (Exception e) {
            e.printStackTrace();
        }
        return md5;
    }

    public static String md5(File file) {
        MessageDigest digest;
        try {
            digest = MessageDigest.getInstance("MD5");
        } catch (NoSuchAlgorithmException e) {
            Log.e(TAG, "Exception while getting digest", e);
            return null;
        }

        InputStream is;
        try {
            is = new FileInputStream(file);
        } catch (FileNotFoundException e) {
            Log.e(TAG, "Exception while getting FileInputStream", e);
            return null;
        }

        byte[] buffer = new byte[8192];
        int read;
        try {
            while ((read = is.read(buffer)) > 0) {
                digest.update(buffer, 0, read);
            }
            byte[] md5sum = digest.digest();
            return md5ToHex(md5sum);
        } catch (IOException e) {
            throw new RuntimeException("Unable to process file for MD5", e);
        } finally {
            try {
                is.close();
            } catch (IOException e) {
                Log.e(TAG, "Exception on closing MD5 input stream", e);
            }
        }
    }

    public static boolean checkMd5(String md5, File file) {
        if (TextUtils.isEmpty(md5) || file == null) {
            Log.e(TAG, "MD5 string empty or file null");
            return false;
        }

        String calculatedDigest = md5(file);
        if (calculatedDigest == null) {
            Log.e(TAG, "calculatedDigest null");
            return false;
        }

        Log.v(TAG, "Calculated digest: " + calculatedDigest);
        Log.v(TAG, "Provided digest: " + md5);

        return calculatedDigest.equalsIgnoreCase(md5);
    }

    private static String md5ToHex(byte[] md5sum) {
        BigInteger bigInt = new BigInteger(1, md5sum);
        String output = bigInt.toString(16);
        // Fill to 32 chars
        return String.format("%32s", output).replace(' ', '0');
    }

    /**
     * 二进制转十六进制
     *
     * @param bytes 数组
     */
    public static String bytesToHex(byte[] bytes, boolean upper) {
        StringBuilder hexStr = new StringBuilder();
        int num;
        for (byte aByte : bytes) {
            num = aByte;
            if (num < 0) {
                num += 256;
            }
            if (num < 16) {
                hexStr.append("0");
            }
            hexStr.append(Integer.toHexString(num));
        }

        if (upper) {
            return hexStr.toString().toUpperCase();
        } else {
            return hexStr.toString();
        }
    }

    /**
     * 二进制转十六进制
     *
     * @param bytes 数组
     */
    private static String bytesToHexUpperCase(byte[] bytes) {
        return bytesToHex(bytes, true);
    }

    /**
     * 二进制转十六进制（小写）
     */
    private static String bytesToHexLowerCase(byte[] bytes) {
        return bytesToHex(bytes, false);
    }

}
